// Copyright Epic Games, Inc. All Rights Reserved.

#include "CommonFuntionBPLibrary.h"
#include "IImageWrapper.h"
#include "IImageWrapperModule.h"
#include "JsonObjectConverter.h"
#include "Engine/TextureRenderTarget2D.h"
//#include <windows.h> 

UCommonFuntionBPLibrary::UCommonFuntionBPLibrary(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

bool UCommonFuntionBPLibrary::JsonStringToStruct(const FString& JsonString, int32& OutputStruct)
{
	check(false);
	return false;
}

bool UCommonFuntionBPLibrary::Generic_JsonStringToStruct(const FString& JsonString, UScriptStruct* OutputType, void* StructPtr)
{
	bool bSuccess = false;
	
	if (JsonString != "" && OutputType && StructPtr)
	{
		TSharedPtr<FJsonObject> JsonObject;
		TSharedRef<TJsonReader<> > JsonReader = TJsonReaderFactory<>::Create(JsonString);
		if (!FJsonSerializer::Deserialize(JsonReader, JsonObject) || !JsonObject.IsValid())
		{
			return false;
		}

		bSuccess = FJsonObjectConverter::JsonObjectToUStruct(JsonObject.ToSharedRef(), OutputType, StructPtr, 0, 0);
	}

	return bSuccess;

}

bool UCommonFuntionBPLibrary::StructToJsonString(const int32& Struct,FString& OutputString)
{
	check(false);
	return false;
}

bool UCommonFuntionBPLibrary::Generic_StructToJsonString(FString& OutputString, UStruct* StructType, const void* StructPtr)
{
	return FJsonObjectConverter::UStructToJsonObjectString(StructType, StructPtr, OutputString, 0, 0);
}

FString UCommonFuntionBPLibrary::UrlEncode(const FString UnencodedString)
{
	static char AllowedChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~:/@#";
	
	static bool AllowedTable[256] = { false };

	for (int32 Idx = 0; Idx < UE_ARRAY_COUNT(AllowedChars) - 1; ++Idx) // -1 to avoid trailing 0
	{
		uint8 AllowedCharIdx = static_cast<uint8>(AllowedChars[Idx]);
		check(AllowedCharIdx < UE_ARRAY_COUNT(AllowedTable));
		AllowedTable[AllowedCharIdx] = true;
	}
	
	FString EncodedString;
	EncodedString.Reserve(UnencodedString.Len()); 

	UTF8CHAR Utf8ConvertedChar[4] = {};
	TCHAR HexChars[3] = { TCHAR('%') };

	for (const TCHAR& InChar : UnencodedString)
	{
		verify(FPlatformString::Convert(Utf8ConvertedChar, sizeof(Utf8ConvertedChar), &InChar, 1));
		for (int32 ByteIdx = 0; ByteIdx < sizeof(Utf8ConvertedChar); ++ByteIdx)
		{
			UTF8CHAR ByteToEncode = Utf8ConvertedChar[ByteIdx];
			Utf8ConvertedChar[ByteIdx] = UTF8CHAR('\0');
			if (ByteToEncode == '\0')
			{
				break;
			}

			if (AllowedTable[ByteToEncode])
			{
				EncodedString.AppendChar(InChar);
			}
			else
			{
				UE::String::BytesToHex(MakeArrayView((uint8*)&ByteToEncode, 1), &HexChars[1]);
				EncodedString.AppendChars(HexChars, 3);
			}
		}
	}

	return EncodedString;
}

FString UCommonFuntionBPLibrary::ExtractSchemeAndAuthority(const FString& URL)
{
	// 创建一个TStringBuilder用于构建结果
	FString Result;

	// 检查是否为绝对URL
	if (URL.StartsWith(TEXT("http://"), ESearchCase::IgnoreCase) || URL.StartsWith(TEXT("https://"), ESearchCase::IgnoreCase))
	{
		// 找到协议结尾的冒号
		int32 ProtocolEndIndex = URL.Find(TEXT("://"), ESearchCase::IgnoreCase) + 3;

		// 找到路径起始的斜杠
		int32 PathStartIndex = URL.Find(TEXT("/"), ESearchCase::IgnoreCase,ESearchDir::FromStart,ProtocolEndIndex);

		// 如果路径起始的斜杠存在，则提取方案名和授权部分
		if (PathStartIndex != INDEX_NONE)
		{
			Result = URL.Left(PathStartIndex);
		}
		else
		{
			// 如果没有找到路径起始的斜杠，则整个URL都是方案名和授权部分
			Result = URL;
		}
	}
	else
	{
		// 如果不是以http://或https://开头，则返回空字符串
		return TEXT("");
	}

	return Result;
}

void UCommonFuntionBPLibrary::ExecuteCMDCommand(FString Parms)
{
	//WinExec(TCHAR_TO_UTF8(*Parms),SW_HIDE);
}

void UCommonFuntionBPLibrary::OpenExe(FString URL)
{
	FProcHandle currHandle = FPlatformProcess::CreateProc(*URL, nullptr, true, false, false, nullptr, 0, nullptr, nullptr);
}

UTexture2D* UCommonFuntionBPLibrary::ConvertRenderTargetToTexture2D(UTextureRenderTarget2D* TextureRenderTarget)
{
	UTexture2D* Texture = UTexture2D::CreateTransient(TextureRenderTarget->SizeX, TextureRenderTarget->SizeY);
	// #if WITH_EDITORONLY_DATA
	// 	Texture->MipGenSettings = TMGS_NoMipmaps;
	// #endif
	Texture->SRGB = false;
	Texture->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
	
	TArray<FColor> SurfData;
	FRenderTarget* RenderTarget = TextureRenderTarget->GameThread_GetRenderTargetResource();
	RenderTarget->ReadPixels(SurfData);
	
	void* TextureData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
	const int32 TextureDataSize = SurfData.Num() * 4;
	FMemory::Memcpy(TextureData, SurfData.GetData(), TextureDataSize);
	Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
	Texture->UpdateResource();

	return Texture;
}

UTexture* UCommonFuntionBPLibrary::LoadTexture2D(const FString& ImagePath, bool& IsValid, int32& OutWidth, int32& OutHeight)
{
	UTexture2D* Texture = nullptr;
	IsValid = false;
	if(!FPlatformFileManager::Get().GetPlatformFile().FileExists(*ImagePath))
	{
		return nullptr;
	}

	TArray<uint8> CompressedData;
	if(!FFileHelper::LoadFileToArray(CompressedData,*ImagePath))
	{
		return nullptr;
	}
	IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
	TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
	if(ImageWrapper.IsValid() && ImageWrapper->SetCompressed(CompressedData.GetData(),CompressedData.Num()))
	{
		TArray<uint8> UncompressedRGBA;;
		if (ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedRGBA))
		{
			Texture = UTexture2D::CreateTransient(ImageWrapper->GetWidth(),ImageWrapper->GetHeight());
			if(Texture != nullptr)
			{
				IsValid = true;
				OutWidth = ImageWrapper->GetWidth();
				OutHeight = ImageWrapper->GetHeight();
				void* TextureData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
				FMemory::Memcpy(TextureData,UncompressedRGBA.GetData(),UncompressedRGBA.Num());
				Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
				Texture->UpdateResource();
			}
		}
	}
	return Texture;
}

bool UCommonFuntionBPLibrary::SaveTexture2D(UTexture2D* Texture, const FString& FilePath)
{
	if (Texture == nullptr)
	{
		return false;
	}

	if(!FPlatformFileManager::Get().GetPlatformFile().FileExists(*FilePath))
	{
		return false;
	}
	
	FTexture2DMipMap& TextureMip = Texture->GetPlatformData()->Mips[0];
	TArray<uint8> RawData;
	RawData.AddUninitialized(TextureMip.SizeX * TextureMip.SizeY * 4);
	void* TextureData = TextureMip.BulkData.Lock(LOCK_READ_WRITE);
	FMemory::Memcpy(RawData.GetData(),TextureData,RawData.Num());
	TextureMip.BulkData.Unlock();

	IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
	TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);

	if(ImageWrapper->SetRaw(RawData.GetData(),RawData.Num(),TextureMip.SizeX,TextureMip.SizeY,ERGBFormat::BGRA,8))
	{
		TArray64<uint8> CompressedData = ImageWrapper->GetCompressed(100);
		if (FFileHelper::SaveArrayToFile(CompressedData,*FilePath))
		{
			return true;
		}
	}
	
	return false;
}

int UCommonFuntionBPLibrary::ChineseNumberToArabicNumber(const FString& ChineseNumber)
{
	if (ChineseNumber.Len() < 1 || !IsValidChineseNumber(ChineseNumber)) return 0;

	if (ChineseNumber[0] == TEXT('负'))
	{
		return -1 * ChineseNumberToArabicNumber(ChineseNumber.RightChop(1));
	}
	
	TMap<TCHAR, int> ChineseNum = {
		{TEXT('零'), 0}, {TEXT('一'), 1}, {TEXT('二'), 2}, {TEXT('三'), 3}, {TEXT('四'), 4},
		{TEXT('五'), 5}, {TEXT('六'), 6}, {TEXT('七'), 7}, {TEXT('八'), 8}, {TEXT('九'), 9}
	};

	TMap<TCHAR, int> ChineseUnit = {
		{TEXT('十'), 10}, {TEXT('百'), 100}, {TEXT('千'), 1000}, {TEXT('万'), 10000}, {TEXT('亿'), 100000000}
	};

	if (ChineseNumber.Len() == 1 && ChineseNumber[0] == TEXT('十'))
	{
		return *ChineseUnit.Find(TEXT('十'));
	}

	int Result = 0, LevelUnit = 1, CurrentUnit = 1;

	for (int i = ChineseNumber.Len() - 1; i > -1; --i)
	{
		const TCHAR& C = ChineseNumber[i];

		if (!ChineseNum.Contains(C) && !ChineseUnit.Contains(C))
			return 0;

		if (ChineseNum.Contains(C))
		{
			Result += *ChineseNum.Find(C) * CurrentUnit;
		}
		else if (ChineseUnit.Contains(C))
		{
			int Unit = *ChineseUnit.Find(C);

			if (Unit > LevelUnit)
			{
				LevelUnit = Unit;
				CurrentUnit = Unit;
			}
			else
			{
				CurrentUnit = LevelUnit * Unit;
			}
		}
	}

	return Result;
}

FString UCommonFuntionBPLibrary::ArabicNumberToChineseNumber(int ArabicNumber)
{
	if (ArabicNumber < 0) return TEXT("负") + ArabicNumberToChineseNumber(-ArabicNumber);
	if (ArabicNumber == 0) return TEXT("零");

	const TCHAR* ChnNumChar[] = {TEXT("零"), TEXT("一"), TEXT("二"), TEXT("三"), TEXT("四"), TEXT("五"), TEXT("六"), TEXT("七"), TEXT("八"), TEXT("九")};
	const TCHAR* ChnUnitChar[] = {TEXT(""),TEXT("十"), TEXT("百"), TEXT("千")};
	const TCHAR* ChnUnitSection[] = {TEXT(""),TEXT("万"), TEXT("亿")};

	TFunction<void(int, FString&)> SectionToChinese = [&](int Section, FString& ChnStr)
	{
		FString strIns;
		int unitPos  = 0;
		bool zero = true;
		while (Section > 0)
		{
			int v = Section % 10;
			if (v == 0)
			{
				if( (Section == 0) || !zero )
				{
					zero = true; /*需要补，zero的作用是确保对连续的多个，只补一个中文零*/
					ChnStr.InsertAt(0, ChnNumChar[v]);
				}
			}
			else
			{
				zero = false; //至少有一个数字不是零
				strIns = ChnNumChar[v]; //此位对应的中文数字
				strIns += ChnUnitChar[unitPos]; //此位对应的中文权位
				ChnStr.InsertAt(0, strIns);
			}
			unitPos++; //移位
			Section = Section / 10;
		}
	};

	FString returnString;
	int unitPos = 0;
	bool needZero = false;
	while (ArabicNumber > 0) {
		unsigned int section = ArabicNumber % 10000;
		FString strIns;
		if (needZero) {
			strIns.InsertAt(0, ChnNumChar[0]);
		}
		SectionToChinese(section, strIns);
		// 是否需要节权位？
		strIns += (section != 0) ? ChnUnitSection[unitPos] : ChnUnitSection[0];
		returnString.InsertAt(0, strIns);
		// 千位是0需要在下一个section补零
		needZero = (section < 1000) && (section > 0);
		ArabicNumber = ArabicNumber / 10000;
		unitPos++;
	}

	return returnString;
}

bool UCommonFuntionBPLibrary::IsValidChineseNumber(const FString& ChineseNumber)
{
	// 如果字符串为空，直接返回无效
	if (ChineseNumber.IsEmpty()) return false;

	FString _0 = TEXT("[零]");
	FString _1_9 = TEXT("[一二三四五六七八九]");
	FString _10_99 = FString::Format(TEXT("{0}?[十]{1}?"),{_1_9,_1_9});
	FString _1_99 = FString::Format(TEXT("({0}|{1})"), {_10_99, _1_9});
	FString _100_999 = FString::Format(TEXT("({0}[百]([零]{1})?|{2}[百]{3})"), {_1_9, _1_9, _1_9, _10_99});
	FString _1_999 = FString::Format(TEXT("({0}|{1})"), {_100_999, _1_99});
	FString _1000_9999 = FString::Format(TEXT("({0}[千]([零]{1})?|{2}[千]{3})"),{_1_9, _1_99, _1_9, _100_999} );
	FString _1_9999 = FString::Format(TEXT("({0}|{1})"), {_1000_9999, _1_999});
	FString _10000_99999999 = FString::Format(TEXT("({0}[万]([零]{1})?|{2}[万]{3})"), {_1_9999, _1_999, _1_9999, _1000_9999});
	FString _1_99999999 = FString::Format(TEXT("({0}|{1})"), {_10000_99999999, _1_9999});
	FString _100000000_9999999999999999 = FString::Format(TEXT("({0}[亿]([零]{1})?|{2}[亿]{3})"), {_1_99999999,_1_99999999,_1_99999999,_10000_99999999});
	FString _1_9999999999999999 = FString::Format(TEXT("({0}|{1})"), {_100000000_9999999999999999,_1_99999999});

	// 组合成最终的正则表达式模式
	FString pattern = FString::Printf(TEXT("^[负]?(%s|%s)$"), *_0, *_1_9999999999999999);

	FRegexPattern ChinesePattern(pattern);
	FRegexMatcher Matcher(ChinesePattern, ChineseNumber);

	return Matcher.FindNext(); // 返回字符串是有效的中文数字
}